package com.note.middleware.listener;

import com.note.middleware.config.RabbitMQConfig;
import com.note.middleware.document.RequestLog;
import com.note.middleware.dto.RequestLogDTO;
import com.note.middleware.repository.RequestLogRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;

/**
 * 请求日志监听器
 * 监听RabbitMQ队列中的日志消息并保存到MongoDB
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class RequestLogListener {

    private final RequestLogRepository requestLogRepository;
    
    /**
     * 监听请求日志队列，处理日志消息
     * 
     * @param logDTO 日志消息
     */
    @RabbitListener(queues = RabbitMQConfig.REQUEST_LOG_QUEUE)
    public void handleRequestLog(RequestLogDTO logDTO) {
        try {
            log.debug("接收到请求日志消息: requestId={}, uri={}", logDTO.getRequestId(), logDTO.getRequestUri());
            
            long startTime = System.currentTimeMillis();
            
            // 构建RequestLog对象
            RequestLog requestLog = buildRequestLog(logDTO);
            
            // 保存到MongoDB
            saveRequestLog(requestLog);
            
            long endTime = System.currentTimeMillis();
            log.debug("请求日志已保存到MongoDB: requestId={}, 耗时={}ms", 
                    logDTO.getRequestId(), (endTime - startTime));
        } catch (Exception e) {
            log.error("处理请求日志消息失败: {}", e.getMessage(), e);
        }
    }
    
    /**
     * 保存请求日志，支持失败重试
     * 重试策略：最多重试3次，初始延迟500ms，后续延迟时间为前一次的1.5倍
     * 
     * @param requestLog 请求日志
     * @return 保存的日志对象
     */
    @Retryable(
        value = {Exception.class},
        exclude = {DuplicateKeyException.class},
        maxAttempts = 3,
        backoff = @Backoff(delay = 500, multiplier = 1.5)
    )
    public RequestLog saveRequestLog(RequestLog requestLog) {
        try {
            return requestLogRepository.save(requestLog);
        } catch (DuplicateKeyException e) {
            log.warn("请求日志已存在，跳过保存: requestId={}", requestLog.getRequestId());
            throw e;
        } catch (Exception e) {
            log.error("保存请求日志失败，将进行重试: requestId={}, error={}", 
                    requestLog.getRequestId(), e.getMessage());
            throw e;
        }
    }
    
    /**
     * 构建RequestLog对象
     * 
     * @param logDTO 日志DTO
     * @return RequestLog对象
     */
    private RequestLog buildRequestLog(RequestLogDTO logDTO) {
        return RequestLog.builder()
                .requestId(logDTO.getRequestId())
                .requestTime(logDTO.getRequestTime())
                .responseTime(logDTO.getResponseTime())
                .processingTime(logDTO.getProcessingTime())
                .requestUri(logDTO.getRequestUri())
                .requestMethod(logDTO.getRequestMethod())
                .requestParams(logDTO.getRequestParams())
                .requestBody(logDTO.getRequestBody())
                .headers(logDTO.getHeaders())
                .clientIp(logDTO.getClientIp())
                .userAgent(logDTO.getUserAgent())
                .responseStatus(logDTO.getResponseStatus())
                .responseBody(logDTO.getResponseBody())
                .hasException(logDTO.getExceptionMessage() != null && !logDTO.getExceptionMessage().isEmpty())
                .exceptionMessage(logDTO.getExceptionMessage())
                .exceptionStack(logDTO.getExceptionStack())
                .userId(logDTO.getUserId())
                .username(logDTO.getUsername())
                .operationType(logDTO.getOperationType())
                .module(logDTO.getModule())
                .description(logDTO.getDescription())
                .createdTime(LocalDateTime.now())
                .build();
    }
} 